from google.appengine.ext import db
from datetime import datetime, timedelta
import urllib2, urllib
from urllib2 import HTTPError
import simplejson
import logging
import config

class NotAuthorizedException(Exception):
    def __init__(self, user):
        self.user = user
    
    def __str__(self):
        return repr('User %s not authorized!', self.user.identity())

class _User(db.Model):
    '''
     User Model with open id
     use key_name value as OpenId identity
    '''
    email = db.EmailProperty(required=False)
    access_token = db.StringProperty(required=False)
    refresh_token = db.StringProperty(required=False)
    expire_date_time = db.DateTimeProperty(required=False)
    
    @property
    def identity(self):
        '''
        get the user's OpenId identity
        '''
        return self.key().name()
    
    def get_access_token(self, force_refresh=False):
        if not self.refresh_token:
            raise NotAuthorizedException(self)
        
        if(self.access_token and self.expire_date_time > datetime.utcnow() and force_refresh == False):
            return self.access_token
        else: # need refresh
            self.update_access_token()
            return self.get_access_token()
            
    def update_access_token(self):
        form = {
                'client_id':config.GOOGLE_OAUTH2_CLIENT_ID,
                'client_secret':config.GOOGLE_OAUTH2_CLIENT_SECRET,
                'refresh_token': self.refresh_token,
                'grant_type':'refresh_token',
                }
        data = urllib.urlencode(form)
        request = urllib2.Request(url='https://accounts.google.com/o/oauth2/token', data=data)
        opener = urllib2.build_opener()
        try:
            resp = opener.open(request)
            resp_data = resp.read()
            logging.info('update access_token_response: %s' % resp_data)
            dic = simplejson.loads(resp_data)
            self.set_tokens(dic['access_token'], dic['expires_in'])
        except HTTPError:
            # failed update token
            self.revoked()
        

    def revoked(self):
        self.access_token = None
        self.expire_date_time = None
        self.refresh_token = None
        self.put()
    
    @classmethod
    def get_or_insert_by_identity(cls, identity, email=None):
        user = cls.get_or_insert(key_name=identity, email=email) #TODO: other fields ? 
        return user
    
    @classmethod
    def delete_by_identity(cls, identity):
        user = cls.get_by_key_name(key_names=identity, parent=None)
        if user: user.delete()
    
    def set_tokens(self, access_token, expires_in, refresh_token=None):
        self.access_token = access_token
        self.expire_date_time = datetime.utcnow() + timedelta(seconds=expires_in)
        if(refresh_token):
            self.refresh_token = refresh_token 
        self.put()
            
    
